using ServiceStack.Logging;
using System;
using System.Collections.Generic;
using System.Threading;
namespace ServiceStack
{
	public static class ExecExtensions
	{
		public static void LogError(Type declaringType, string clientMethodName, Exception ex)
		{
			LogManager.GetLogger(declaringType).Error(string.Format("'{0}' threw an error on {1}: {2}", declaringType.FullName, clientMethodName, ex.Message), ex);
		}
		public static void ExecAll<T>(this IEnumerable<T> instances, Action<T> action)
		{
			foreach (T current in instances)
			{
				try
				{
					action(current);
				}
				catch (Exception ex)
				{
					ExecExtensions.LogError(current.GetType(), action.GetType().Name, ex);
				}
			}
		}
		public static void ExecAllWithFirstOut<T, TReturn>(this IEnumerable<T> instances, Func<T, TReturn> action, ref TReturn firstResult)
		{
			foreach (T current in instances)
			{
				try
				{
					TReturn tReturn = action(current);
					if (!object.Equals(firstResult, default(TReturn)))
					{
						firstResult = tReturn;
					}
				}
				catch (Exception ex)
				{
					ExecExtensions.LogError(current.GetType(), action.GetType().Name, ex);
				}
			}
		}
		public static TReturn ExecReturnFirstWithResult<T, TReturn>(this IEnumerable<T> instances, Func<T, TReturn> action)
		{
			foreach (T current in instances)
			{
				try
				{
					TReturn tReturn = action(current);
					object arg_2C_0 = tReturn;
					TReturn tReturn2 = default(TReturn);
					if (!object.Equals(arg_2C_0, tReturn2))
					{
						tReturn2 = tReturn;
						return tReturn2;
					}
				}
				catch (Exception ex)
				{
					ExecExtensions.LogError(current.GetType(), action.GetType().Name, ex);
				}
			}
			return default(TReturn);
		}
		public static void RetryUntilTrue(Func<bool> action, TimeSpan? timeOut)
		{
			int num = 0;
			DateTime utcNow = DateTime.UtcNow;
			while (!timeOut.HasValue || DateTime.UtcNow - utcNow < timeOut.Value)
			{
				num++;
				if (action())
				{
					return;
				}
				ExecExtensions.SleepBackOffMultiplier(num);
			}
			throw new TimeoutException(string.Format("Exceeded timeout of {0}", timeOut.Value));
		}
		public static void RetryOnException(Action action, TimeSpan? timeOut)
		{
			int num = 0;
			Exception innerException = null;
			DateTime utcNow = DateTime.UtcNow;
			while (!timeOut.HasValue || DateTime.UtcNow - utcNow < timeOut.Value)
			{
				num++;
				try
				{
					action();
					return;
				}
				catch (Exception innerException)
				{
					ExecExtensions.SleepBackOffMultiplier(num);
				}
			}
			throw new TimeoutException(string.Format("Exceeded timeout of {0}", timeOut.Value), innerException);
		}
		public static void RetryOnException(Action action, int maxRetries)
		{
			for (int i = 0; i < maxRetries; i++)
			{
				try
				{
					action();
					break;
				}
				catch
				{
					if (i == maxRetries - 1)
					{
						throw;
					}
					ExecExtensions.SleepBackOffMultiplier(i);
				}
			}
		}
		private static void SleepBackOffMultiplier(int i)
		{
			Thread.Sleep(new Random(Guid.NewGuid().GetHashCode()).Next((int)Math.Pow((double)i, 2.0), (int)Math.Pow((double)(i + 1), 2.0) + 1));
		}
	}
}
